package com.jsptpd.smartauth.modules.business.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.jsptpd.smartauth.common.util.HashUtils;
import com.jsptpd.smartauth.common.util.JWTUtil;
import com.jsptpd.smartauth.common.util.StringUtil;
import com.jsptpd.smartauth.common.util.WeChatUtil;
import com.jsptpd.smartauth.modules.business.dao.db1.BindInfoMapper;
import com.jsptpd.smartauth.modules.business.model.BindInfo;
import com.jsptpd.smartauth.modules.business.model.Error;
import com.jsptpd.smartauth.modules.business.model.LoginLock;
import com.jsptpd.smartauth.modules.business.model.RespObj;
import com.jsptpd.smartauth.modules.business.model.User;
import com.jsptpd.smartauth.modules.business.model.WeChatToken;
import com.jsptpd.smartauth.modules.business.service.ILoginLockService;
import com.jsptpd.smartauth.modules.business.service.ILoginService;
import com.jsptpd.smartauth.modules.business.service.IUserService;
import com.jsptpd.smartauth.modules.business.utils.Constants;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class LoginServiceImpl extends ServiceImpl<BindInfoMapper, BindInfo> implements ILoginService {

    @Value("${config.login.succ}")
    private String cfgLoginSucc;
    @Value("${config.login.errBind}")
    private String cfgLoginErrBind;
    @Value("${config.login.errState}")
    private String cfgLoginErrState;
    @Value("${config.login.errToken}")
    private String cfgLoginErrToken;
    @Value("${config.login.errQRcode}")
    private String cfgLoginErrQRcode;
    @Value("${config.login.errExp}")
    private String cfgLoginErrExp;
    @Value("${config.login.errEnd}")
    private String cfgLoginErrEnd;
    @Value("${config.login.errUser}")
    private String cfgLoginErrUser;
    @Value("${config.login.errJwt}")
    private String cfgLoginErrJwt;
    @Value("${config.login.errPwd}")
    private String cfgLoginErrPwd;

    @Value("${config.login.lock.limit}")
    private Integer lockLimit;
    @Value("${config.login.lock.frozen}")
    private Integer lockFrozken;
    @Value("${config.login.lock.tips.locked}")
    private String cfgLockTipsLocked;
    @Value("${config.login.lock.tips.lockwarn}")
    private String cfgLockTipsLockWarn;

    private WeChatUtil weChatUtil = new WeChatUtil();

    @Autowired
    IUserService userService;
    @Autowired
    ILoginLockService loginLockService;

    @Override
    public RespObj loginWithAccount(String userId, String password) {
        Error error;
        //参数判断是否为空
        if(userId==null || userId.isEmpty() || password==null || password.isEmpty()){
            error = new Error(Constants.LOGIN_ERRCODE_STATE,Constants.LOGIN_ERRMSG_STATE);
            return new RespObj<String>(error,"");
        }

        User user = userService.findByUserIdPlus(userId);
        if(user==null){
            error = new Error(Constants.LOGIN_ERRCODE_NOUSER,Constants.LOGIN_ERRMSG_NOUSER);
            return new RespObj<String>(error,"");
        }
        //Add by Andy On Jane 16th for login lock:
        List<LoginLock> listLock = loginLockService.getByUserId(userId);
        if(listLock!=null && listLock.size()>0){
            long timeDelta = (new Date().getTime()-listLock.get(0).getUpdateTime().getTime())/(1000*60);
            if(timeDelta>lockFrozken){
                loginLockService.removeByUserId(userId);
            }else{
                if(listLock.get(0).getCount()>=lockLimit){
                    long restMinute = lockFrozken - timeDelta;
                    String restTime = restMinute + "分钟";
                    restTime = getHourMinuteFormat(restMinute, restTime);
                    error = new Error(Constants.LOGIN_ERRCODE_LOCKED,
                            String.format(StringUtil.getValue(cfgLockTipsLocked,Constants.LOGIN_ERRMSG_LOCKED),restTime));
                    return new RespObj<String>(error,"");
                }
            }
        }

        //检查用户是否有效
        if (StringUtil.equalUpperCase(user.getPassword(), HashUtils.shaPwd(password))) {
            //登录成功
            loginLockService.removeByUserId(userId);

            if(userService.validate(user.getUserId())){
                error = new Error(Constants.LOGIN_ERRCODE_SUCC,StringUtil.getValue(cfgLoginSucc,Constants.LOGIN_ERRMSG_SUCC));
                return new RespObj<String>(error,user.getUserId());
            }else{
                error = new Error(Constants.LOGIN_ERRCODE_END,StringUtil.getValue(cfgLoginErrEnd,Constants.LOGIN_ERRMSG_END));
                return new RespObj<String>(error,"");
            }
        }
        //登录失败
        int errorLoginCount;
        listLock = loginLockService.getByUserId(userId);
        if(listLock!=null && listLock.size()>0){
            LoginLock loginLock = listLock.get(0);
            errorLoginCount = loginLock.getCount()+1;
            loginLock.setCount(errorLoginCount);
            loginLock.setUpdateTime(new Date());
            loginLockService.updateByUserId(loginLock);

        }else{
            LoginLock loginLock = new LoginLock();
            loginLock.setId(UUID.randomUUID().toString());
            loginLock.setUserId(userId);
            errorLoginCount = 1;
            loginLock.setCount(errorLoginCount);
            loginLock.setUpdateTime(new Date());
            loginLockService.insertByUserId(loginLock);
        }
        /*error = new Error(Constants.LOGIN_ERRCODE_INVALID_PWD,StringUtil.getValue(cfgLoginErrPwd,Constants.LOGIN_ERRMSG_INVALID_PWD));*/
        if(errorLoginCount>=lockLimit){
            long restMinute = lockFrozken;
            String restTime = restMinute + "分钟";
            restTime = getHourMinuteFormat(restMinute, restTime);
            error = new Error(Constants.LOGIN_ERRCODE_LOCKED,
                    String.format(StringUtil.getValue(cfgLockTipsLocked,Constants.LOGIN_ERRMSG_LOCKED),restTime));
        }else{
            error = new Error(Constants.LOGIN_ERRCODE_LOCKWARN,
                    String.format(StringUtil.getValue(cfgLockTipsLockWarn,Constants.LOGIN_ERRMSG_LOCKWARN),lockLimit-errorLoginCount));
        }

        return new RespObj<String>(error,"");
    }

    private String getHourMinuteFormat(long restMinute, String restTime) {
        if(restMinute>=60){
            Integer restHour = Math.toIntExact(restMinute / 60);
            if(restMinute == restHour*60){
                restTime = restHour + "小时";
            }else {
                restTime = restHour + "小时" + (restMinute - restHour * 60) + "分钟";
            }
        }
        return restTime;
    }

    @Override
    public RespObj loginWithWechat(String code, String state,String appId) throws IOException {
        Error error = new Error();
        RespObj<String> respData = new RespObj<String>(error,"");

        if(appId==null || appId.isEmpty()){
            respData.getError().setErrCode(Constants.LOGIN_ERRCODE_STATE);
            respData.getError().setErrMessage(StringUtil.getValue(cfgLoginErrState,Constants.LOGIN_ERRMSG_STATE));
            return respData;
        }

        if (code != null) {
            //根据code获取token
            WeChatToken weChatToken = weChatUtil.getWxTokenByCode(code,appId);

            if (weChatToken!=null
                    && StringUtil.isEmpty(weChatToken.getErrCode())
                    && StringUtil.isNotEmpty(weChatToken.getUnionId())) {
                if (state!=null) {
                    BindInfo bi = selectOne(new EntityWrapper<BindInfo>()
                            .where("UNION_ID={0} AND STATUS!={1}", weChatToken.getUnionId(),Constants.WX_BIND_STATUS_WAIT)
                            .orderBy("CREATE_TIME",false));//CREATE_TIME

                    if (bi == null) { //尚未绑定
                        respData.getError().setErrCode(Constants.LOGIN_ERRCODE_BIND);
                        respData.getError().setErrMessage(StringUtil.getValue(cfgLoginErrBind,Constants.LOGIN_ERRMSG_BIND));
                    } else if(bi.getStatus() == Constants.WX_BIND_STATUS_DONE){ //已绑定并有效
                        //检查用户是否有效
                        if(userService.validate(bi.getUserId())){
                            respData.getError().setErrCode(Constants.LOGIN_ERRCODE_SUCC);
                            respData.getError().setErrMessage(StringUtil.getValue(cfgLoginSucc,Constants.LOGIN_ERRMSG_SUCC));
                            respData.setData(bi.getUserId());
                        }else{
                            respData.getError().setErrCode(Constants.LOGIN_ERRCODE_END);
                            respData.getError().setErrMessage(StringUtil.getValue(cfgLoginErrEnd,Constants.LOGIN_ERRMSG_END));
                        }
                    } else {
                        respData.getError().setErrCode(Constants.LOGIN_ERRCODE_EXP);
                        respData.getError().setErrMessage(StringUtil.getValue(cfgLoginErrExp,Constants.LOGIN_ERRMSG_EXP));
                    }
                } else {
                    respData.getError().setErrCode(Constants.LOGIN_ERRCODE_STATE);
                    respData.getError().setErrMessage(StringUtil.getValue(cfgLoginErrState,Constants.LOGIN_ERRMSG_STATE));
                }
            } else {
                respData.getError().setErrCode(Constants.LOGIN_ERRCODE_TOKEN);
                respData.getError().setErrMessage(String.format(StringUtil.getValue(cfgLoginErrToken,Constants.LOGIN_ERRMSG_TOKEN),weChatToken.getErrCode()));
            }
        } else {
            respData.getError().setErrCode(Constants.LOGIN_ERRCODE_QRCODE);
            respData.getError().setErrMessage(StringUtil.getValue(cfgLoginErrQRcode,Constants.LOGIN_ERRMSG_QRCODE));
        }

        return respData;
    }

    @Override
    public RespObj loginWithToken(String userId,String tokenId) {
        Error error;
        if (userId==null || userId.isEmpty()) {
            error = new Error(Constants.LOGIN_ERRCODE_STATE,StringUtil.getValue(cfgLoginErrState,Constants.LOGIN_ERRMSG_STATE));
            return new RespObj<String>(error,"");
        } else if (tokenId==null || tokenId.isEmpty()) {
            error = new Error(Constants.LOGIN_ERRCODE_JWT, StringUtil.getValue(cfgLoginErrJwt, Constants.LOGIN_ERRMSG_JWT));
            return new RespObj<String>(error, "");
        } else {
            String userUid = JWTUtil.getAppUID(tokenId);
            if (userUid!=null && userUid.equals(userId)) {
                //检查用户是否有效
                if (userService.validate(userId)) {
                    error = new Error(Constants.LOGIN_ERRCODE_SUCC, StringUtil.getValue(cfgLoginSucc, Constants.LOGIN_ERRMSG_SUCC));
                    return new RespObj<String>(error, userId);
                } else {
                    error = new Error(Constants.LOGIN_ERRCODE_END, StringUtil.getValue(cfgLoginErrEnd, Constants.LOGIN_ERRMSG_END));
                    return new RespObj<String>(error, "");
                }
            } else {
                error = new Error(Constants.LOGIN_ERRCODE_JWT,StringUtil.getValue(cfgLoginErrJwt,Constants.LOGIN_ERRMSG_JWT));
                return new RespObj<String>(error,"");
            }
        }
    }
}
